//Version = 1.0.9

// здесь создаем объект-обертку, дабы не загрязнять глобальное пространство имен
let loader = {}

// теперь добавляем нашу функцию в этот объект
// uri - полный адрес к удаленному JS файлу

loader.importJS = async function (uri, async = false) {
  return new Promise(function (resolve, reject) {
    const s = document.createElement('script');
    let r = false;
    s.type = 'text/javascript';
    s.src = uri;
    s.async = async;
    s.onerror = function (err) {
      reject(err, s);
    };
    s.onload = s.onreadystatechange = function () {
      // console.log(this.readyState); // uncomment this line to see which ready states are called.
      if (!r && (!this.readyState || this.readyState == 'complete')) {
        r = true;
        resolve();
      }
    };
    const t = document.getElementsByTagName('script')[0];
    t.parentElement.insertBefore(s, t);
  });
}

function fib(n, r = [0, 1]) {
  return n <= 0 ? r[0] + r[1] : fib(n - 1, [r[1], r[0] + r[1]])
}//Возвращает число "n" из последовательности Фибоначчи

function Random(min, max) {
  if (typeof (min) === 'number') { min = min } else { min = 0 };
  if (typeof (max) === 'number') { max = max } else { max = 1 };
  return Math.floor(Math.random() * (max - min + 1)) + min;
}
//Возвращает коллекцию случайных, не повторяющихся чисел.
function rndMass(randLength, min, max) {
  var randArray = [],
    inArray = function (arr, num) {
      for (var i = 0; i < arr.length; i++) {
        if (num == arr[i]) return true;
      }
      return false;
    },
    i = 0;
  if (randLength > (max - min + 1)) {
    return null;
  }
  var x = 0;
  while (i < randLength) {
    x++;
    var rand = Math.floor(Math.random() * (max - min + 1)) + min;
    if (!(inArray(randArray, rand))) {
      i++;
      randArray.unshift(rand);
    }
  }
  //alert([randLength,x]); //длина и число генераций
  return randArray;
}

// возвращает cookie с именем name, если есть, если нет, то undefined
function getCookie(name) {
  var matches = document.cookie.match(new RegExp(
    "(?:^|; )" + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + "=([^;]*)"
  ));
  return matches ? decodeURIComponent(matches[1]) : undefined;
}

// перемешивает элементы массива
function shuffleArr(arr) {
  var j, temp;
  for (var i = arr.length - 1; i > 0; i--) {
    j = Math.floor(Math.random() * (i + 1));
    temp = arr[j];
    arr[j] = arr[i];
    arr[i] = temp;
  }
  return arr;
}

//Функция для воспроизведения звука по url. Так же позволяет запустить звук при загрузке страницы в обход защиты браузера.
function playSound(url, seek = 0) {
  // var audio = document.createElement('embed');
  // audio.src = url;
  // audio.style = "width:0px;height:0px";
  // document.body.appendChild(audio);
  let audio = new Audio();
  audio.canPlayType('audio/mp3');
  audio.src = url;
  audio.play()
  return audio;
}

function Player(url, callback) {
  let audioP = new Audio();
  let AfterPlay = callback || '';
  audioP.src = url;
  let playPromise = audioP.play();
  if (playPromise !== null) {
    playPromise.catch(() => { setTimeout(() => audioP.play(), 3000, audioP) })
  }
  audioP.onended = AfterPlay;
  return audioP;
}

async function PlaySoundWebApi(url, seek = 0, callback = null) {
  let self = {};
  self.seek = seek;
  self.callback = callback;
  self.context = new AudioContext();
  self.source = null;
  let decodedAudioData;
  if (!self.context) {
    console.warn('Web Audio API: AudioContext not found.');
    return
  }
  let arrayBufferawait = await (await fetch(url)).arrayBuffer();
  let audioBuffer = await self.context.decodeAudioData(arrayBufferawait);
  self.decodedAudioData = audioBuffer;

  self.source = self.context.createBufferSource();
  self.source.buffer = self.decodedAudioData;
  self.source.connect(self.context.destination);

  self.play = function (callback = self.callback, startTime = self.seek) {
    // Устанавливаем время воспроизведения
    self.source.start(0, startTime);

    // Подписываемся на событие окончания воспроизведения
    self.source.onended = function () {
      if (callback) callback(self.source);
      console.log('Воспроизведение окончено');
    };
  }

  self.stop = function () { self.source.stop() }
  return self;
}

const inArray = (arr, val) => arr.flat(Infinity).includes(val);
const inArrayIndex = (arr, val) => arr.flat(Infinity).indexOf(val);

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

function msg(text, time = 0, audio = '', options = {}) {
  let params = {
    animation: 'flip',
    color: "black",
    content: text,
    delayOnHover: true,
    showCountdown: true,
    offset: {
      y: 50
    }
  }
  if (Object.keys(options).length) params = { ...params, ...options }
  if (time) params.autoClose = false;
  if (audio) params.audio = audio;

  let m = new jBox('Notice', params);

  if (time) setTimeout(() => m.close(), time * 1000);
  return m;
}

function DTimer(options) {
  let start = options.start || "00:00:00";
  let finish = options.finish || "23:59:59";
  let relate = options.relate || new Date();
  let diffin = 0;
  let intid = 0;

  start = Date.parse(start);
  finish = Date.parse(finish);
  relate = Date.parse(relate);

  const DATE = 86400000;
  const HOUR = 3600000;
  const MINUTE = 60000;
  const SECOND = 1000;
  const MSECND = 1;

  this.running = false;

  this.fixTime = function (time) {

    return (time < 10 && (time > 0 || time == 0) ? "0" + time : time);

  };

  this.start = function (started, end_callback) {

    let self = this, count = 1;
    if (relate < start || relate > finish) return 0;

    intid = setInterval(
      function () {

        diffin = finish - (relate + SECOND * count);

        if (diffin < 0)
          self.stop();
        else
          self.running = true;

        if (self.running === true) {

          started.call(self, {
            getDate: function () { return Math.floor(diffin / DATE) },
            getHours: function () { return Math.floor(diffin % DATE / HOUR) },
            getMinutes: function () { return Math.floor(diffin % HOUR / MINUTE) },
            getSeconds: function () { return Math.floor(diffin % MINUTE / SECOND) },
            getMilliseconds: function () { return Math.floor(diffin % SECOND / MSECND) }
          });

        } else {
          end_callback();
        }

        count++;

      }, SECOND
    );

  };

  this.stop = function () {
    this.running = false;
    clearInterval(intid);
    console.log("stop interval");
  };
  return this;
  // Example:
  /*
  var dt = new DTimer({
    start:  "2015/12/01",
    finish: "2016/01/01",
    relate: "2015/12/31 23:59:00:00"
  });
  
  dt.start(function( date){
    console.log("DTimer -> " + 
                //this.fixTime(date.getYear()) + "/" +
                //this.fixTime(date.getMonth()) + "/" + 
                this.fixTime(date.getDate()) + " " + 
                this.fixTime(date.getHours()) + ":" + 
                this.fixTime(date.getMinutes()) + ":" + 
                this.fixTime(date.getSeconds())
               );
  }, function(){
  console.log('Р—Р°РїСѓСЃРє Р°РЅРёРјР°С†РёРё');
  });
  */
}

function addZero(num, lenght = 2) {
  var str = num.toString();
  while (str.length < lenght) {
    str = "0" + str;
  }
  return str;
}